package com.guodi.model.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.guodi.model.entity.*;
import com.guodi.model.service.*;
import com.guodi.model.utils.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import javax.annotation.Resource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class IdtValueExportServiceImpl implements IIdtValueExportService {

    @Resource
    private IIdtIndicatorsTypeService iIdtIndicatorsTypeService;
    @Resource
    private IIdtIndicatorsService iIdtIndicatorsService;
    @Resource
    private IIdtIndicatorsDirService idtIndicatorsDirService;
    @Resource
    private IIdtReportValueService iIdtReportValueService;
    @Resource
    private IIdtMonitorValueService idtMonitorValueService;

    /**
     * 基本指标 类型名
     * */
    private static final String IDT_TYPE_BASIC = "basic";
    /**
     * 推荐指标 类型名
     * */
    private static final String IDT_TYPE_RECOMMEND = "recommend";
    /**
     * 地方指标 类型名
     * */
    private static final String IDT_TYPE_PLACE = "place";

    /**
     * 指标范围 值 全域
     * */
    private static final String IDT_SCOPE_ALL = "all";
    /**
     * 指标范围 值 城区
     * */
    private static final String IDT_SCOPE_CITY = "city";

    /***
     * @描述: 导出【体检评估_导出报告.xls】
     * @入参: idtTypeCode 指标体系编码，非空必填
     * @入参: divisionCode 行政区划，非空必填
     * @入参: orgId 组织单位id，如果不为空，则只返回责任单位为该单位及其子单位的指标
     * @入参: idtType 指标类型，不为空时会过滤指标
     * @入参: keyWord 关键词，不为空时会根据指标名和指标编号过滤，
     * @入参: idtStatus 指标状态，不为空时过滤
     * @入参: startYear 开始年份
     * @入参: endYear 结束年份
     * @出参: 【体检评估_导出报告.xls】
     * @作者: 陈宏成
     * @日期: 2021/02/02
     */
    public void exportAssessmentExcel (HttpServletResponse response, String idtTypeCode, String divisionCode, String orgId, String idtType, String keyWord, String idtStatus, String startYear, String endYear, String idtTypeId){
        // 行政区划
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        // 年份集合
        List<Integer> yearList = null;
        //获取指标列表
        List<ApiIdtIndicatorsDir> apiIdtIndicatorsDirs = idtIndicatorsDirService.listIdtDirForReport(idtTypeCode, orgId, idtType, keyWord, idtStatus, divisionCode, idtTypeId);
        List<ApiIdtIndicatorsDir> dirList = null;
        List<ApiIdtIndicatorsDir> idtList = null;
        if(apiIdtIndicatorsDirs == null || apiIdtIndicatorsDirs.isEmpty()){
            idtList = new LinkedList<>();
            yearList = new LinkedList<>();
        }else{
            IdtIndicatorsType iIdtIndicatorsType = iIdtIndicatorsTypeService.getById(idtTypeId);
            //进行排序
            apiIdtIndicatorsDirs = SortUtil.sortList(apiIdtIndicatorsDirs, iIdtIndicatorsType.getId(), 1);
            // 过滤目录
            dirList = apiIdtIndicatorsDirs.stream().filter(idtDir -> idtDir.getType() == 1).collect(Collectors.toList());
            // 过滤指标
            idtList = apiIdtIndicatorsDirs.stream().filter(idtDir -> idtDir.getType() == 2).collect(Collectors.toList());
            // 指标id列表
            List<String> idtIdList = idtList.stream().map(ApiIdtIndicatorsDir::getIndicatorsId).collect(Collectors.toList());

            // 寻找年份范围
            // 上报年份范围
            QueryWrapper<IdtReportValue> queryWrapper1 = new QueryWrapper();
            queryWrapper1.select("distinct year");
            queryWrapper1.in("indicators_id", idtIdList);
            queryWrapper1.eq("division_code", divisionCode);
            queryWrapper1.ge(StringUtils.hasText(startYear),"year",StringUtils.hasText(startYear)? Integer.parseInt(startYear): startYear);
            queryWrapper1.le(StringUtils.hasText(endYear),"year",StringUtils.hasText(endYear)? Integer.parseInt(endYear): endYear);
            queryWrapper1.orderByAsc("year");
            List<IdtReportValue> reportYearList = iIdtReportValueService.list(queryWrapper1);
            // 年份集合
            Set<Integer> yearSet = reportYearList.stream().map(IdtReportValue::getYear).collect(Collectors.toSet());
            yearList = yearSet.stream().sorted().collect(Collectors.toList());
        }
        // 组织单位map
        Map<String, String> deptMap = iIdtIndicatorsService.getDeptNameMap();
        // 填充Excel数据
        List<Object[]> excelDataList = new ArrayList<>(idtList.size());
        for(int i = 0; i < idtList.size(); i++) {
            ApiIdtIndicatorsDir apiIdtIndicatorsDir = idtList.get(i);
            Object[] rowData = new Object[11 + yearList.size() * 2];
            // 基本信息
            rowData[0] = i + 1;
            rowData[5] = this.convertNullStringToLine(apiIdtIndicatorsDir.getIdtCode(),"");
            rowData[6] = this.convertNullStringToLine(apiIdtIndicatorsDir.getIdtUnit(),"");
            rowData[7] = this.convertNullStringToLine(this.getIdtScopeName(apiIdtIndicatorsDir.getIdtScope()),"");
            rowData[8] = this.convertNullStringToLine(this.getIdtTypeName(apiIdtIndicatorsDir.getIdtType()),"");
            //
            rowData[9] = deptMap.getOrDefault(apiIdtIndicatorsDir.getIdtDutyCompany(),"");
            rowData[10] = deptMap.getOrDefault(apiIdtIndicatorsDir.getIdtDutyDepartment(),"");
            // 查询各年的指标值
            QueryWrapper<IdtMonitorValue> queryWrapper3 = null;
            QueryWrapper<IdtReportValue> queryWrapper4 = null;
            int index = 0;
            for(Integer year : yearList) {
                // 监测值
                queryWrapper3 = new QueryWrapper();
                queryWrapper3.eq("indicators_id", apiIdtIndicatorsDir.getIndicatorsId());
                queryWrapper3.eq("division_code", divisionCode);
                queryWrapper3.eq("year", year);
                queryWrapper3.orderByDesc("create_time");
                List<IdtMonitorValue> monitorValues = idtMonitorValueService.list(queryWrapper3);
                rowData[10 + index * 2 + 1] = monitorValues == null || monitorValues.size() <= 0? "":this.holdTwoDecimal(monitorValues.get(0).getMonitorValue());
                // 上报值
                queryWrapper4 = new QueryWrapper();
                queryWrapper4.eq("indicators_id", apiIdtIndicatorsDir.getIndicatorsId());
                queryWrapper4.eq("division_code", divisionCode);
                queryWrapper4.eq("year", year);
                queryWrapper4.orderByDesc("create_time");
                List<IdtReportValue> reportValues = iIdtReportValueService.list(queryWrapper4);
                rowData[10 + index * 2 + 2] = reportValues == null || reportValues.size() <= 0? "":this.holdTwoDecimal(reportValues.get(0).getValue());

                index++;
            }
            // 指标名称
            // 寻找当前指标的上级目录
            int[] titleFieldsIndex = {1,2,3,4};
            List<String> titleValues = new LinkedList<>();
            titleValues.add( this.convertNullStringToLine(apiIdtIndicatorsDir.getIdtName(),"") );
            StringBuilder parentId = new StringBuilder(apiIdtIndicatorsDir.getParentId());
            // 寻找上级目录
            while(true){
                ApiIdtIndicatorsDir parentDir = dirList.stream().filter(dir -> dir.getId().equals(parentId.toString())).findAny().orElse(null);
                if(parentDir == null){
                    break;
                }else{
                    titleValues.add(0,parentDir.getName());
                    parentId.delete(0,parentId.length());
                    parentId.append(parentDir.getParentId());
                }
            }
            // 将上级目录放入map
            for(int j = 0,titleValuesIndex = 0; j < titleFieldsIndex.length; j++, titleValuesIndex++) {
                int titleFieldsInde = titleFieldsIndex[j];
                if(titleValuesIndex < titleValues.size()){
                    rowData[titleFieldsInde] =  titleValues.get(titleValuesIndex);
                }else{
                    rowData[titleFieldsInde] = null;
                }
            }
            excelDataList.add(rowData);
        }
        // 处理单元格标题
        List<List<String>> titleConfigs = new LinkedList<>();
        titleConfigs.add(Arrays.asList("0","0","0","1","序号"));
        titleConfigs.add(Arrays.asList("1","4","0","1","指标名称"));
        titleConfigs.add(Arrays.asList("5","5","0","1","指标编号"));
        titleConfigs.add(Arrays.asList("6","6","0","1","单位"));
        titleConfigs.add(Arrays.asList("7","7","0","1","范围"));
        titleConfigs.add(Arrays.asList("8","8","0","1","指标类别"));
        titleConfigs.add(Arrays.asList("9","9","0","1","责任单位"));
        titleConfigs.add(Arrays.asList("10","10","0","1","责任处室"));
        titleConfigs.addAll(this.buildMergeCellsForExcel(new int[]{1,2,3,4},excelDataList,2));
        // 年份和监测值、上报值的标题
        int index = 0;
        for(Integer year : yearList) {
            titleConfigs.add(Arrays.asList(String.valueOf(10 + index * 2 + 1),String.valueOf(10 + index * 2 + 2),"0","0",year + "年"));
            titleConfigs.add(Arrays.asList(String.valueOf(10 + index * 2 + 1),String.valueOf(10 + index * 2 + 1),"1","1","监测值"));
            titleConfigs.add(Arrays.asList(String.valueOf(10 + index * 2 + 2),String.valueOf(10 + index * 2 + 2),"1","1","上报值"));
            index++;
        }
        // 生成表格
        ExcelUtil.exportExcel(response,divisionText+"体检评估报告","sheet", titleConfigs ,excelDataList,2);
    }

    /**
     * @描述: 导出【指标监测值】Excel
     * @作者: 陈宏成
     * @日期: 2021/01/21
     **/
    @Override
    public void exportMonitorValueExcel(HttpServletResponse response, String code, String divisionCode, Integer year, String orgId, String particularYear){
        //获取根据编码获取体系类型
        IdtIndicatorsType iIdtIndicatorsType = iIdtIndicatorsTypeService.findByCode(code, particularYear, divisionCode);
        // 行政区划
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        //获取父节点下的所有数据
        List<ApiIdtIndicatorsDir> listData = idtIndicatorsDirService.listDirByCode(iIdtIndicatorsType.getId(), null, null);
        // 排序，按照层级和各层级中的排序进行
        listData = SortUtil.sortList(listData, iIdtIndicatorsType.getId(), 1);
        // 查指标数值
        if (listData != null && listData.size() > 0) {
            listData.parallelStream().forEach(idtDir -> {
                if (idtDir.getType() == 2) {
                    ApiIndicatorsVal apiIndicatorsVal = iIdtIndicatorsService.getIdtVal(idtDir.getIndicatorsId(), String.valueOf(year), divisionCode, false, false);
                    // 20210908添加预警规则逻辑处理
                    if(null != apiIndicatorsVal && org.apache.commons.lang.StringUtils.isNotBlank(apiIndicatorsVal.getWarnRuleConfig())){
                        String warnStatus = iIdtIndicatorsService.updateWarnStatus(apiIndicatorsVal);
                        apiIndicatorsVal.setWarnStatus(warnStatus);
                    }else {
                        apiIndicatorsVal.setWarnStatus("null,尚未配置规则");
                    }
                    idtDir.setApiIndicatorsVal(apiIndicatorsVal);
                }
            });
        }
        // 抽取指标项
        List<ApiIdtIndicatorsDir> indicatorsList = listData.stream().filter(dir -> dir.getType() == 2).collect(Collectors.toList());
        // 抽取目录项
        List<ApiIdtIndicatorsDir> dirList = listData.stream().filter(dir -> dir.getType() == 1).collect(Collectors.toList());
        // 处理表格数据
        List<Object[]> excelDataList = new ArrayList<>(indicatorsList.size());
        // 遍历指标项
        for(int i = 0; i < indicatorsList.size(); i++) {
            ApiIdtIndicatorsDir indicators = indicatorsList.get(i);
            Object[] rowData = new Object[10];
            // 处理空数据
            rowData[4] = indicators.getApiIndicatorsVal().getMonitorYear()==null?"":indicators.getApiIndicatorsVal().getMonitorValue();
            rowData[5] = indicators.getApiIndicatorsVal().getBaseYear()==null?"":indicators.getApiIndicatorsVal().getBaseValue();
            rowData[6] = indicators.getApiIndicatorsVal().getTargetYear()==null?"":indicators.getApiIndicatorsVal().getTargetValue();
            rowData[7] = indicators.getIdtUnit()==null?"":indicators.getIdtUnit();
            rowData[8] = indicators.getApiIndicatorsVal().getWarnStatus();
            // ========= 以下代码的目的是为了处理不同层级的指标的单元格合并问题，例如下面这三种 ========
            // |                         指标名                             |  监测值  |
            // |                   |                  |    土地总面积        |  1      |
            // |      资源条件      |     自然资源现状    |    建设用地面积      |  1      |
            // |                   |                  |    城乡建设用地面积   |  1      |
            // |                   |             固定资产投资总额             |  1      |
            // |                        建设用地剩余空间                      |  1      |
            // 寻找当前指标的上级目录，假设指标层级关系最多只有4级，titleFieldsIndex 指标目录名所在的列的下标
            int[] titleFieldsIndex = {0,1,2,3};
            // 指标名的层级列表，[上上上级指标，上上级指标，上级指标，指标]
            List<String> titleValues = new LinkedList<>();
            titleValues.add(indicators.getIdtName() == null ? "" : indicators.getIdtName() );
            // 这里 parentId 使用StringBuilder主要是因为 dirList.stream().filter()里面用到parentId，匿名内部类只能用final修饰过的外部变量，如果用String会报错的
            StringBuilder parentId = new StringBuilder(indicators.getParentId());
            // 寻找上级目录
            while(true){
                ApiIdtIndicatorsDir parentDir = dirList.stream().filter(dir -> dir.getId().equals(parentId.toString())).findAny().orElse(null);
                if(parentDir == null){
                    break;
                }else{
                    titleValues.add(0,parentDir.getName());
                    // 相当于 parentId = parentDir.getParentId()
                    parentId.delete(0,parentId.length());
                    parentId.append(parentDir.getParentId());
                }
            }
            // 将上级目录放入map
            // titleValuesIndex 为 titleValues的 的下标，用于依次获取指标名
            // titleFieldsInde 为 Excel中指标名列的下标，用于获取列的下标
            for(int j = 0,titleValuesIndex = 0; j < titleFieldsIndex.length; j++, titleValuesIndex++) {
                // 依次获取每个指标目录名所在的列的下标
                int titleFieldsInde = titleFieldsIndex[j];
                if(titleValuesIndex < titleValues.size()){
                    rowData[titleFieldsInde] =  titleValues.get(titleValuesIndex);
                }else{
                    // 后面合并横向单元格是需要判断null的
                    rowData[titleFieldsInde] = null;
                }
            }
            excelDataList.add(rowData);
        }
        // 处理单元格标题
        List<List<String>> titleConfigs = new LinkedList<>();
        titleConfigs.add(Arrays.asList("0","3","0","0","指标名称","c","b"));
        titleConfigs.add(Arrays.asList("4","4","0","0","监测值","l","b"));
        titleConfigs.add(Arrays.asList("5","5","0","0","基期值","l","b"));
        titleConfigs.add(Arrays.asList("6","6","0","0","规划目标值","l","b"));
        titleConfigs.add(Arrays.asList("7","7","0","0","单位","l","b"));
        titleConfigs.add(Arrays.asList("8","8","0","0","预警状态","l","b"));
        titleConfigs.addAll(this.buildMergeCellsForExcel(new int[]{0,1,2,3},excelDataList,1));
        // 处理单元格的字体颜色
        List<String[]> colorCellList = new LinkedList<>();
        for(int i = 0; i < excelDataList.size(); i++) {
            Object[] rowData = excelDataList.get(i);
            // 20210908更改指标预警规则字体颜色
            if(null != rowData[8]){
                String[] warnStatus = rowData[8].toString().split(",");
                if(warnStatus.length == 1){
                    // 如果不包含逗号，说明可能是3.1版本旧数据没有更新
                    if("预警".equals((String)(rowData[8]))){
                        colorCellList.add( new String[]{String.valueOf(8),String.valueOf(8),String.valueOf(i+1),String.valueOf(i+1),"#f93e3e"});
                    }else if("正常".equals((String)(rowData[8]))){
                        colorCellList.add( new String[]{String.valueOf(8),String.valueOf(8),String.valueOf(i+1),String.valueOf(i+1),"#13ce66"});
                    }
                }else if(warnStatus.length == 2){
                    // 说明是版本3.2的指标预警规则
                    colorCellList.add( new String[]{String.valueOf(8),String.valueOf(8),String.valueOf(i+1),String.valueOf(i+1),warnStatus[0].equals("null")?"#000000":warnStatus[0]});
                    rowData[8] = warnStatus[1];
                }
            }
        }
        // 序号列要求居中对齐
        List<String[]> alignCellList = new LinkedList<>();
        ExcelUtil.exportExcel(response,divisionText+"监测数值报告（"+year+"年）","sheet", titleConfigs ,excelDataList,1,colorCellList,alignCellList);
    }

    @Override
    public void exportTargetValueExcel(HttpServletResponse response, String code, String divisionCode, String year, String orgId, String particularYear) {
        //获取根据编码获取体系类型
        IdtIndicatorsType iIdtIndicatorsType = iIdtIndicatorsTypeService.findByCode(code, particularYear, divisionCode);
        // 行政区划
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        //获取父节点下的所有数据
        List<ApiIdtIndicatorsDir> resultList = idtIndicatorsDirService.listDirByCode(iIdtIndicatorsType.getId(), null, null);

        //进行排序
        List<ApiIdtIndicatorsDir> listData = SortUtil.sortList(resultList, iIdtIndicatorsType.getId(), 1);

        if (listData != null && listData.size() > 0) {
            listData.parallelStream().forEach(idtDir -> {
                if (idtDir.getType() == 2) {
                    ApiIndicatorsVal apiIndicatorsVal = iIdtIndicatorsService.getIdtVal(idtDir.getIndicatorsId(), year, divisionCode,false, false);
                    apiIndicatorsVal.setValue(this.holdTwoDecimal(apiIndicatorsVal.getValue()));
                    apiIndicatorsVal.setTargetValue(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue()));
                    apiIndicatorsVal.setBaseValue(this.holdTwoDecimal(apiIndicatorsVal.getBaseValue()));
                    apiIndicatorsVal.setMonitorValue(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue()));
                    idtDir.setApiIndicatorsVal(apiIndicatorsVal);
                }
            });
        }
        // 抽取指标项
        List<ApiIdtIndicatorsDir> indicatorsList = listData.stream().filter(dir -> dir.getType() == 2).collect(Collectors.toList());
        // 抽取目录项
        List<ApiIdtIndicatorsDir> dirList = listData.stream().filter(dir -> dir.getType() == 1).collect(Collectors.toList());
        // 处理表格数据
        List<Object[]> excelDataList = new ArrayList<>(indicatorsList.size());
        // 遍历指标项
        for(int i = 0; i < indicatorsList.size(); i++) {
            ApiIdtIndicatorsDir indicators = indicatorsList.get(i);
            Object[] rowData = new Object[11];
            rowData[0] = i+1;
            rowData[5] = indicators.getApiIndicatorsVal().getUnit()==null?"":indicators.getApiIndicatorsVal().getUnit();
            rowData[6] = indicators.getApiIndicatorsVal().getBaseYear()==null?"":indicators.getApiIndicatorsVal().getBaseYear();
            rowData[7] = indicators.getApiIndicatorsVal().getBaseValue()==null?"":indicators.getApiIndicatorsVal().getBaseValue();
            rowData[8] = indicators.getApiIndicatorsVal().getTargetYear()==null?"":indicators.getApiIndicatorsVal().getTargetYear();
            rowData[9] = indicators.getApiIndicatorsVal().getTargetValue()==null?"":indicators.getApiIndicatorsVal().getTargetValue();
            rowData[10] = org.apache.commons.lang.StringUtils.isBlank(indicators.getApiIndicatorsVal().getTargetExplain())?"--":indicators.getApiIndicatorsVal().getTargetExplain();
            // 寻找当前指标的上级目录
            int[] titleFieldsIndex = {1,2,3,4};
            List<String> titleValues = new LinkedList<>();
            titleValues.add(indicators.getIdtName() == null ? "" : indicators.getIdtName() );
            StringBuilder parentId = new StringBuilder(indicators.getParentId());
            // 寻找上级目录
            while(true){
                ApiIdtIndicatorsDir parentDir = dirList.stream().filter(dir -> dir.getId().equals(parentId.toString())).findAny().orElse(null);
                if(parentDir == null){
                    break;
                }else{
                    titleValues.add(0,parentDir.getName());
                    parentId.delete(0,parentId.length());
                    parentId.append(parentDir.getParentId());
                }
            }
            // 将上级目录放入map
            for(int j = 0,titleValuesIndex = 0; j < titleFieldsIndex.length; j++, titleValuesIndex++) {
                int titleFieldsInde = titleFieldsIndex[j];
                if(titleValuesIndex < titleValues.size()){
                    rowData[titleFieldsInde] =  titleValues.get(titleValuesIndex);
                }else{
                    rowData[titleFieldsInde] = null;
                }
            }
            excelDataList.add(rowData);
        }
        // 处理单元格标题
        List<List<String>> titleConfigs = new LinkedList<>();
        titleConfigs.add(Arrays.asList("0","0","0","0","序号"));
        titleConfigs.add(Arrays.asList("1","4","0","0","指标名称"));
        titleConfigs.add(Arrays.asList("5","5","0","0","单位"));
        titleConfigs.add(Arrays.asList("6","6","0","0","基期年份"));
        titleConfigs.add(Arrays.asList("7","7","0","0","基期值"));
        titleConfigs.add(Arrays.asList("8","8","0","0","规划目标年份"));
        titleConfigs.add(Arrays.asList("9","9","0","0","规划目标值"));
        titleConfigs.add(Arrays.asList("10","10","0","0","规划值说明"));
        titleConfigs.addAll(this.buildMergeCellsForExcel(new int[]{1,2,3,4},excelDataList,1));
        // 处理单元格的字体颜色
        List<String[]> colorCellList = new LinkedList<>();
        ExcelUtil.exportExcel(response,divisionText+"规划目标数值报告（"+year+"年）","sheet", titleConfigs ,excelDataList,1,colorCellList);
    }

    @Override
    public HSSFWorkbook getTargetValueExcelByte(String code, String divisionCode, String year, String orgId) {
        //获取根据编码获取体系类型--此方法已弃用
        IdtIndicatorsType iIdtIndicatorsType = iIdtIndicatorsTypeService.findByCode(code, year, divisionCode);
        // 行政区划
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        //获取父节点下的所有数据
        List<ApiIdtIndicatorsDir> resultList = idtIndicatorsDirService.listDirByCode(iIdtIndicatorsType.getId(), null, null);

        //进行排序
        List<ApiIdtIndicatorsDir> listData = SortUtil.sortList(resultList, iIdtIndicatorsType.getId(), 1);

        if (listData != null && listData.size() > 0) {
            listData.parallelStream().forEach(idtDir -> {
                if (idtDir.getType() == 2) {
                    ApiIndicatorsVal apiIndicatorsVal = iIdtIndicatorsService.getIdtVal(idtDir.getIndicatorsId(), year, divisionCode, false, false);
                    apiIndicatorsVal.setValue(this.holdTwoDecimal(apiIndicatorsVal.getValue()));
                    apiIndicatorsVal.setTargetValue(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue()));
                    apiIndicatorsVal.setBaseValue(this.holdTwoDecimal(apiIndicatorsVal.getBaseValue()));
                    apiIndicatorsVal.setMonitorValue(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue()));
                    idtDir.setApiIndicatorsVal(apiIndicatorsVal);
                }
            });
        }
        // 抽取指标项
        List<ApiIdtIndicatorsDir> indicatorsList = listData.stream().filter(dir -> dir.getType() == 2).collect(Collectors.toList());
        // 抽取目录项
        List<ApiIdtIndicatorsDir> dirList = listData.stream().filter(dir -> dir.getType() == 1).collect(Collectors.toList());
        // 处理表格数据
        List<Object[]> excelDataList = new ArrayList<>(indicatorsList.size());
        // 遍历指标项
        for(int i = 0; i < indicatorsList.size(); i++) {
            ApiIdtIndicatorsDir indicators = indicatorsList.get(i);
            Object[] rowData = new Object[11];
            rowData[0] = i+1;
            rowData[5] = indicators.getApiIndicatorsVal().getUnit()==null?"":indicators.getApiIndicatorsVal().getUnit();
            rowData[6] = indicators.getApiIndicatorsVal().getBaseYear()==null?"":indicators.getApiIndicatorsVal().getBaseYear();
            rowData[7] = indicators.getApiIndicatorsVal().getBaseValue()==null?"":indicators.getApiIndicatorsVal().getBaseValue();
            rowData[8] = indicators.getApiIndicatorsVal().getTargetYear()==null?"":indicators.getApiIndicatorsVal().getTargetYear();
            rowData[9] = indicators.getApiIndicatorsVal().getTargetValue()==null?"":indicators.getApiIndicatorsVal().getTargetValue();
            rowData[10] = org.apache.commons.lang.StringUtils.isBlank(indicators.getApiIndicatorsVal().getTargetExplain())?"--":indicators.getApiIndicatorsVal().getTargetExplain();
            // 寻找当前指标的上级目录
            int[] titleFieldsIndex = {1,2,3,4};
            List<String> titleValues = new LinkedList<>();
            titleValues.add(indicators.getIdtName() == null ? "" : indicators.getIdtName() );
            StringBuilder parentId = new StringBuilder(indicators.getParentId());
            // 寻找上级目录
            while(true){
                ApiIdtIndicatorsDir parentDir = dirList.stream().filter(dir -> dir.getId().equals(parentId.toString())).findAny().orElse(null);
                if(parentDir == null){
                    break;
                }else{
                    titleValues.add(0,parentDir.getName());
                    parentId.delete(0,parentId.length());
                    parentId.append(parentDir.getParentId());
                }
            }
            // 将上级目录放入map
            for(int j = 0,titleValuesIndex = 0; j < titleFieldsIndex.length; j++, titleValuesIndex++) {
                int titleFieldsInde = titleFieldsIndex[j];
                if(titleValuesIndex < titleValues.size()){
                    rowData[titleFieldsInde] =  titleValues.get(titleValuesIndex);
                }else{
                    rowData[titleFieldsInde] = null;
                }
            }
            excelDataList.add(rowData);
        }
        // 处理单元格标题
        List<List<String>> titleConfigs = new LinkedList<>();
        titleConfigs.add(Arrays.asList("0","0","0","0","序号"));
        titleConfigs.add(Arrays.asList("1","4","0","0","指标名称"));
        titleConfigs.add(Arrays.asList("5","5","0","0","单位"));
        titleConfigs.add(Arrays.asList("6","6","0","0","基期年份"));
        titleConfigs.add(Arrays.asList("7","7","0","0","基期值"));
        titleConfigs.add(Arrays.asList("8","8","0","0","规划目标年份"));
        titleConfigs.add(Arrays.asList("9","9","0","0","规划目标值"));
        titleConfigs.add(Arrays.asList("10","10","0","0","规划值说明"));
        titleConfigs.addAll(this.buildMergeCellsForExcel(new int[]{1,2,3,4},excelDataList,1));
        // 处理单元格的字体颜色
        List<String[]> colorCellList = new LinkedList<>();
        return ExcelUtil.exportExcel("sheet", titleConfigs ,excelDataList,1,colorCellList);
    }

    @Override
    public void exportReportValueExcel(HttpServletResponse response, String code, String divisionCode, String year, String orgId, String particularYear) {
        // 是否是多个年份
        boolean isMoreYear = false;
        String[] yearArr = null;
        if (year.split("-") != null && year.split("-").length > 1) {
            isMoreYear = true;
            yearArr = year.split("-");
        }
        //获取根据编码获取体系类型
        IdtIndicatorsType iIdtIndicatorsType = iIdtIndicatorsTypeService.findByCode(code, particularYear, divisionCode);
        // 行政区划
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        //获取父节点下的所有数据
        List<ApiIdtIndicatorsDir> resultList = idtIndicatorsDirService.listDirByCode(iIdtIndicatorsType.getId(), null, null);

        //进行排序
        List<ApiIdtIndicatorsDir> listData = SortUtil.sortList(resultList, iIdtIndicatorsType.getId(), 1);

        if (listData != null && listData.size() > 0) {
            for (ApiIdtIndicatorsDir idtDir : listData) {
                if (idtDir.getType() == 2) {
                    if (isMoreYear) {
                        // 多年份指标数值
                        List<ApiIndicatorsVal> apiIndicatorsValList = iIdtIndicatorsService.listRangeIdtVal(idtDir.getIndicatorsId(), yearArr[0], yearArr[1], divisionCode, false, true);
                        if (apiIndicatorsValList != null && apiIndicatorsValList.size() > 0) {
                            for (ApiIndicatorsVal apiIndicatorsVal : apiIndicatorsValList) {
                                apiIndicatorsVal.setValue(this.holdTwoDecimal(apiIndicatorsVal.getValue()));
                                apiIndicatorsVal.setTargetValue(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue()));
                                apiIndicatorsVal.setBaseValue(this.holdTwoDecimal(apiIndicatorsVal.getBaseValue()));
                                apiIndicatorsVal.setMonitorValue(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue()));
                            }
                        }
                        idtDir.setApiIndicatorsValList(apiIndicatorsValList);
                    } else {
                        // 单年份指标数值
                        ApiIndicatorsVal apiIndicatorsVal = iIdtIndicatorsService.getIdtVal(idtDir.getIndicatorsId(), year, divisionCode, false, true);
                        apiIndicatorsVal.setValue(this.holdTwoDecimal(apiIndicatorsVal.getValue()));
                        apiIndicatorsVal.setTargetValue(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue()));
                        apiIndicatorsVal.setBaseValue(this.holdTwoDecimal(apiIndicatorsVal.getBaseValue()));
                        apiIndicatorsVal.setMonitorValue(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue()));
                        idtDir.setApiIndicatorsVal(apiIndicatorsVal);
                    }
                }
            }
        }
        // 抽取指标项
        List<ApiIdtIndicatorsDir> indicatorsList = listData.stream().filter(dir -> dir.getType() == 2).collect(Collectors.toList());
        // 抽取目录项
        List<ApiIdtIndicatorsDir> dirList = listData.stream().filter(dir -> dir.getType() == 1).collect(Collectors.toList());
        // 处理表格数据
        List<Object[]> excelDataList = new ArrayList<>(indicatorsList.size());
        // 遍历指标项
        for(int i = 0; i < indicatorsList.size(); i++) {
            ApiIdtIndicatorsDir indicators = indicatorsList.get(i);
            Object[] rowData = null;
            if (isMoreYear) {
                rowData = new Object[11];
                rowData[0] = i+1;
                rowData[5] = indicators.getApiIndicatorsValList().get(0).getUnit()==null?"":indicators.getApiIndicatorsValList().get(0).getUnit();
                rowData[6] = indicators.getApiIndicatorsValList().get(0).getValue()==null?"":indicators.getApiIndicatorsValList().get(0).getValue();
                rowData[7] = indicators.getApiIndicatorsValList().get(1).getValue()==null?"":indicators.getApiIndicatorsValList().get(1).getValue();
                rowData[8] = indicators.getApiIndicatorsValList().get(2).getValue()==null?"":indicators.getApiIndicatorsValList().get(2).getValue();
                rowData[9] = indicators.getApiIndicatorsValList().get(3).getValue()==null?"":indicators.getApiIndicatorsValList().get(3).getValue();
                rowData[10] = indicators.getApiIndicatorsValList().get(4).getValue()==null?"":indicators.getApiIndicatorsValList().get(4).getValue();
            } else {
                rowData = new Object[8];
                rowData[0] = i+1;
                rowData[5] = indicators.getApiIndicatorsVal().getUnit()==null?"":indicators.getApiIndicatorsVal().getUnit();
                rowData[6] = indicators.getApiIndicatorsVal().getValue()==null?"":indicators.getApiIndicatorsVal().getValue();
                rowData[7] = indicators.getApiIndicatorsVal().getReportExplain()==null?"":indicators.getApiIndicatorsVal().getReportExplain();
            }

            // 寻找当前指标的上级目录
            int[] titleFieldsIndex = {1,2,3,4};
            List<String> titleValues = new LinkedList<>();
            titleValues.add(indicators.getIdtName() == null ? "" : indicators.getIdtName() );
            StringBuilder parentId = new StringBuilder(indicators.getParentId());
            // 寻找上级目录
            while(true){
                ApiIdtIndicatorsDir parentDir = dirList.stream().filter(dir -> dir.getId().equals(parentId.toString())).findAny().orElse(null);
                if(parentDir == null){
                    break;
                }else{
                    titleValues.add(0,parentDir.getName());
                    parentId.delete(0,parentId.length());
                    parentId.append(parentDir.getParentId());
                }
            }
            // 将上级目录放入map
            for(int j = 0,titleValuesIndex = 0; j < titleFieldsIndex.length; j++, titleValuesIndex++) {
                int titleFieldsInde = titleFieldsIndex[j];
                if(titleValuesIndex < titleValues.size()){
                    rowData[titleFieldsInde] =  titleValues.get(titleValuesIndex);
                }else{
                    rowData[titleFieldsInde] = null;
                }
            }
            excelDataList.add(rowData);
        }
        // 处理单元格标题
        List<List<String>> titleConfigs = new LinkedList<>();
        if (isMoreYear) {
            titleConfigs.add(Arrays.asList("0", "0", "0", "0", "序号"));
            titleConfigs.add(Arrays.asList("1", "4", "0", "0", "指标名称"));
            titleConfigs.add(Arrays.asList("5", "5", "0", "0", "单位"));
            int star = Integer.valueOf(yearArr[0]);
            int end = Integer.valueOf(yearArr[1]);
            int index = 6;
            for (int j = star; j <= end; j++) {
                titleConfigs.add(Arrays.asList(String.valueOf(index), String.valueOf(index), "0", "0", j + "年"));
                index++;
            }
            titleConfigs.addAll(this.buildMergeCellsForExcel(new int[]{1, 2, 3, 4}, excelDataList, 1));
        } else {
            titleConfigs.add(Arrays.asList("0", "0", "0", "0", "序号"));
            titleConfigs.add(Arrays.asList("1", "4", "0", "0", "指标名称"));
            titleConfigs.add(Arrays.asList("5", "5", "0", "0", "单位"));
            titleConfigs.add(Arrays.asList("6", "6", "0", "0", year + "年"));
            titleConfigs.add(Arrays.asList("7", "7", "0", "0", "评估值说明"));
            titleConfigs.addAll(this.buildMergeCellsForExcel(new int[]{1, 2, 3, 4}, excelDataList, 1));
        }
        // 处理单元格的字体颜色
        List<String[]> colorCellList = new LinkedList<>();
        ExcelUtil.exportExcel(response,divisionText+"现状评估上报数值报告（"+year+"年）","sheet", titleConfigs ,excelDataList,1,colorCellList);
    }

    @Override
    public HSSFWorkbook getReportValueExcelByte(String code, String divisionCode, String year, String orgId) {
        // 是否是多个年份
        boolean isMoreYear = false;
        String[] yearArr = null;
        if (year.split("-") != null && year.split("-").length > 1) {
            isMoreYear = true;
            yearArr = year.split("-");
        }

        //获取根据编码获取体系类型--此方法已弃用
        IdtIndicatorsType iIdtIndicatorsType = iIdtIndicatorsTypeService.findByCode(code, year, divisionCode);
        // 行政区划
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        //获取父节点下的所有数据
        List<ApiIdtIndicatorsDir> resultList = idtIndicatorsDirService.listDirByCode(iIdtIndicatorsType.getId(), null, null);

        //进行排序
        List<ApiIdtIndicatorsDir> listData = SortUtil.sortList(resultList, iIdtIndicatorsType.getId(), 1);

        if (listData != null && listData.size() > 0) {
            for (ApiIdtIndicatorsDir idtDir : listData) {
                if (idtDir.getType() == 2) {
                    if (isMoreYear) {
                        // 多年份指标数值
                        List<ApiIndicatorsVal> apiIndicatorsValList = iIdtIndicatorsService.listRangeIdtVal(idtDir.getIndicatorsId(), yearArr[0], yearArr[1], divisionCode, false, true);
                        if (apiIndicatorsValList != null && apiIndicatorsValList.size() > 0) {
                            for (ApiIndicatorsVal apiIndicatorsVal : apiIndicatorsValList) {
                                apiIndicatorsVal.setValue(this.holdTwoDecimal(apiIndicatorsVal.getValue()));
                                apiIndicatorsVal.setTargetValue(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue()));
                                apiIndicatorsVal.setBaseValue(this.holdTwoDecimal(apiIndicatorsVal.getBaseValue()));
                                apiIndicatorsVal.setMonitorValue(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue()));
                            }
                        }
                        idtDir.setApiIndicatorsValList(apiIndicatorsValList);
                    } else {
                        // 单年份指标数值
                        ApiIndicatorsVal apiIndicatorsVal = iIdtIndicatorsService.getIdtVal(idtDir.getIndicatorsId(), year, divisionCode, false, true);
                        apiIndicatorsVal.setValue(this.holdTwoDecimal(apiIndicatorsVal.getValue()));
                        apiIndicatorsVal.setTargetValue(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue()));
                        apiIndicatorsVal.setBaseValue(this.holdTwoDecimal(apiIndicatorsVal.getBaseValue()));
                        apiIndicatorsVal.setMonitorValue(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue()));
                        idtDir.setApiIndicatorsVal(apiIndicatorsVal);
                    }
                }
            }
        }
        // 抽取指标项
        List<ApiIdtIndicatorsDir> indicatorsList = listData.stream().filter(dir -> dir.getType() == 2).collect(Collectors.toList());
        // 抽取目录项
        List<ApiIdtIndicatorsDir> dirList = listData.stream().filter(dir -> dir.getType() == 1).collect(Collectors.toList());
        // 处理表格数据
        List<Object[]> excelDataList = new ArrayList<>(indicatorsList.size());
        // 遍历指标项
        for(int i = 0; i < indicatorsList.size(); i++) {
            ApiIdtIndicatorsDir indicators = indicatorsList.get(i);
            Object[] rowData = null;
            if (isMoreYear) {
                rowData = new Object[11];
                rowData[0] = i+1;
                rowData[5] = indicators.getApiIndicatorsValList().get(0).getUnit()==null?"":indicators.getApiIndicatorsValList().get(0).getUnit();
                rowData[6] = indicators.getApiIndicatorsValList().get(0).getValue()==null?"":indicators.getApiIndicatorsValList().get(0).getValue();
                rowData[7] = indicators.getApiIndicatorsValList().get(1).getValue()==null?"":indicators.getApiIndicatorsValList().get(1).getValue();
                rowData[8] = indicators.getApiIndicatorsValList().get(2).getValue()==null?"":indicators.getApiIndicatorsValList().get(2).getValue();
                rowData[9] = indicators.getApiIndicatorsValList().get(3).getValue()==null?"":indicators.getApiIndicatorsValList().get(3).getValue();
                rowData[10] = indicators.getApiIndicatorsValList().get(4).getValue()==null?"":indicators.getApiIndicatorsValList().get(4).getValue();
            } else {
                rowData = new Object[8];
                rowData[0] = i+1;
                rowData[5] = indicators.getApiIndicatorsVal().getUnit()==null?"":indicators.getApiIndicatorsVal().getUnit();
                rowData[6] = indicators.getApiIndicatorsVal().getValue()==null?"":indicators.getApiIndicatorsVal().getValue();
                rowData[7] = indicators.getApiIndicatorsVal().getReportExplain()==null?"":indicators.getApiIndicatorsVal().getReportExplain();
            }

            // 寻找当前指标的上级目录
            int[] titleFieldsIndex = {1,2,3,4};
            List<String> titleValues = new LinkedList<>();
            titleValues.add(indicators.getIdtName() == null ? "" : indicators.getIdtName() );
            StringBuilder parentId = new StringBuilder(indicators.getParentId());
            // 寻找上级目录
            while(true){
                ApiIdtIndicatorsDir parentDir = dirList.stream().filter(dir -> dir.getId().equals(parentId.toString())).findAny().orElse(null);
                if(parentDir == null){
                    break;
                }else{
                    titleValues.add(0,parentDir.getName());
                    parentId.delete(0,parentId.length());
                    parentId.append(parentDir.getParentId());
                }
            }
            // 将上级目录放入map
            for(int j = 0,titleValuesIndex = 0; j < titleFieldsIndex.length; j++, titleValuesIndex++) {
                int titleFieldsInde = titleFieldsIndex[j];
                if(titleValuesIndex < titleValues.size()){
                    rowData[titleFieldsInde] =  titleValues.get(titleValuesIndex);
                }else{
                    rowData[titleFieldsInde] = null;
                }
            }
            excelDataList.add(rowData);
        }
        // 处理单元格标题
        List<List<String>> titleConfigs = new LinkedList<>();
        if (isMoreYear) {
            titleConfigs.add(Arrays.asList("0", "0", "0", "0", "序号"));
            titleConfigs.add(Arrays.asList("1", "4", "0", "0", "指标名称"));
            titleConfigs.add(Arrays.asList("5", "5", "0", "0", "单位"));
            int star = Integer.valueOf(yearArr[0]);
            int end = Integer.valueOf(yearArr[1]);
            int index = 6;
            for (int j = star; j <= end; j++) {
                titleConfigs.add(Arrays.asList(String.valueOf(index), String.valueOf(index), "0", "0", j + "年"));
                index++;
            }
            titleConfigs.addAll(this.buildMergeCellsForExcel(new int[]{1, 2, 3, 4}, excelDataList, 1));
        } else {
            titleConfigs.add(Arrays.asList("0", "0", "0", "0", "序号"));
            titleConfigs.add(Arrays.asList("1", "4", "0", "0", "指标名称"));
            titleConfigs.add(Arrays.asList("5", "5", "0", "0", "单位"));
            titleConfigs.add(Arrays.asList("6", "6", "0", "0", year + "年"));
            titleConfigs.add(Arrays.asList("7", "7", "0", "0", "评估值说明"));
            titleConfigs.addAll(this.buildMergeCellsForExcel(new int[]{1, 2, 3, 4}, excelDataList, 1));
        }
        // 处理单元格的字体颜色
        List<String[]> colorCellList = new LinkedList<>();
        return ExcelUtil.exportExcel("sheet", titleConfigs ,excelDataList,1,colorCellList);
    }

    /**
     * 构建合并单元格，主要是为了构建com.guodi.model.utils.ExcelUtil#exportExcel(HttpServletResponse, String, String, List, List, int)这个方法的第四个参数。<br/>
     * 合并数据项中的单元格。<br/>
     * 纵向合并是通过判断单元格的值是否相同，上下连续单元格的值相同，且左侧一列的单元格也是相同的，就合并。<br/>
     * 横向合并是通过判断null，如果单元格为null，就往左侧单元格合并。<br/>
     * @入参: mergeIndexs 数据项中要合并的列的下标 ，{0,1,2,3}，注意，这里的下标是从0开始的
     * @入参: excelDataList 数据列表
     * @入参: dataRowStartIndex 数据列开始行的下标
     * @出参: 数据项中合并的单元格
     * @作者: 陈宏成
     * @日期: 2021/01/21
     **/
    private List<List<String>> buildMergeCellsForExcel(int[] mergeIndexs, List<Object[]> excelDataList, int dataRowStartIndex){
        List<List<String>> mergeTableCellList = new LinkedList<>();
        int rowStart = 0, rowEnd = 0, colStart = 0, colEnd = 0;
        // 每列纵向合并
        for(int mergeIndex : mergeIndexs) {
            rowStart = dataRowStartIndex;
            rowEnd = dataRowStartIndex;
            colStart = mergeIndex;
            colEnd = mergeIndex;
            // 遍历所有行
            String title = null;            // 上一单元格的值
            String titleParent = null;      // 上一单元格左侧单元格的值
            for(int i = 0; i < excelDataList.size(); i++) {
                Object[] data = excelDataList.get(i);
                // 获取当前列的单元格值
                String tempTitle =  (String)data[mergeIndex];
                // 获取左边一列的单元格值
                String tempParentTitle =  mergeIndex > 0? String.valueOf(data[mergeIndex-1]) : null;
                if(title == null){
                    // 如果是第一行，直接赋值
                    title = tempTitle;
                    titleParent = tempParentTitle;
                } else if ((title.equals(tempTitle) && mergeIndex == mergeIndexs[0])  || (title.equals(tempTitle) && titleParent.equals(tempParentTitle) && mergeIndex > mergeIndexs[0])){
                    // 同时也判断一下和左侧单元格是否相等，主要是为了防止当前单元格一样，但是左侧单元格不同，从而导致交叉合并单元格。如果是第一列，则没有左侧单元格，所以不用比较。
                    // 例如下面，虽然“打游戏”是一样，但是由于前面不同，所以他们归属不同的分类，不能做纵向合并，
                    // |    爱好    |    打游戏    |
                    // |    职业    |    打游戏    |
                    rowEnd++;
                    // 如果是最后一条记录，直接添加一个合并单元格
                    if(i == excelDataList.size() - 1){
                        mergeTableCellList.add(Arrays.asList(String.valueOf(colStart),String.valueOf(colEnd),String.valueOf(rowStart),String.valueOf(rowEnd),tempTitle));
                    }
                }else{
                    // 不满足合并条件，即和下一个单元格不同
                    // 添加一个合并单元格
                    mergeTableCellList.add(Arrays.asList(String.valueOf(colStart),String.valueOf(colEnd),String.valueOf(rowStart),String.valueOf(rowEnd),title));
                    // 记录当前的文本内容
                    title = tempTitle;
                    titleParent = tempParentTitle;
                    // 重置四个下标
                    rowStart = i + dataRowStartIndex;
                    rowEnd = rowStart;
                }
            }
        }
        // 横向合并，如果指标名称为空，则则与左边单元格进行合并
        for(int i = 0; i < excelDataList.size(); i++) {
            rowStart = dataRowStartIndex + i;
            rowEnd = rowStart;
            colStart = mergeIndexs[mergeIndexs.length - 1];
            colEnd = colStart;
            Object[] data = excelDataList.get(i);
            // [上上上级单元格，上上级单元格，上级单元格，单元格] ，初始只有最右侧的单元格，依次往左扩展单元格数量
            for(int j = mergeIndexs.length - 1; j >= 0; j--) {
                String tempTitle = (String)data[mergeIndexs[j]];
                if (tempTitle == null){
                    colStart--;
                }else{
                    break;
                }
            }
            mergeTableCellList.add(Arrays.asList(String.valueOf(colStart),String.valueOf(colEnd),String.valueOf(rowStart),String.valueOf(rowEnd),String.valueOf(data[colStart])));
        }
        return mergeTableCellList;
    }

    /**
     * @描述: 导出【国土空间规划监测评估预警报告】word报告
     * @作者: 陈宏成
     * @日期: 2021/01/20
     **/
    @Override
    public void exportMonitorWarningReport(HttpServletResponse response, String indicatorsTypeCode,  String divisionCode,Integer year, String orgId, String particularYear){
        // 获取行政区划
        String divisionText = this.idtMonitorValueService.getNameByDivisionCode(divisionCode);
        //获取根据编码获取体系类型
        IdtIndicatorsType one = iIdtIndicatorsTypeService.findByCode(indicatorsTypeCode, particularYear, divisionCode);
        //获取父节点下的所有数据
        List<ApiIdtIndicatorsDir> indicatorsDirList = idtIndicatorsDirService.listDirByCode(one.getId(), null,null);
        // 排序
        indicatorsDirList = SortUtil.sortList(indicatorsDirList, one.getId(), 1);
        // 查指标数值
        indicatorsDirList.parallelStream().forEach((idtDir)->{
            if(idtDir.getType()==2){
                // 单年份指标数值
                ApiIndicatorsVal apiIndicatorsVal = iIdtIndicatorsService.getIdtVal(idtDir.getIndicatorsId(), String.valueOf(year), divisionCode, false,false);
                apiIndicatorsVal.setValue(this.holdTwoDecimal(apiIndicatorsVal.getValue()));
                apiIndicatorsVal.setTargetValue(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue()));
                apiIndicatorsVal.setBaseValue(this.holdTwoDecimal(apiIndicatorsVal.getBaseValue()));
                apiIndicatorsVal.setMonitorValue(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue()));
                idtDir.setApiIndicatorsVal(apiIndicatorsVal);
            }
        });
        String docxFileUrl = null;
        try{
            // word文档
            String docxName = this.exportMonitorWarningReportWord(indicatorsDirList, divisionCode, year);
            docxFileUrl = FileUtil.tempFilePath + docxName;
            // 文件名
            String newExportFileName = divisionText+"国土空间规划监测评估报告（"+ String.valueOf(year) +"年）" ;
            // 导出
            InputStream inputStream = new FileInputStream(docxFileUrl);
            response.setContentType("application/octet-stream;charset=UTF-8;");
            response.setHeader("Content-Disposition", "attachment; filename=\"" +  new String(newExportFileName.getBytes(),"iso-8859-1") + ".docx"+ "\"");
            ServletOutputStream outputStream = response.getOutputStream();
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(bytes)) > 0){
                outputStream.write(bytes,0,len);
            }
            inputStream.close();
            outputStream.flush();
            outputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(docxFileUrl != null){
                FileUtil.deleteFile(docxFileUrl);
            }
        }
    }

    @Override
    public String getMonitorWarningReportPath(String indicatorsTypeCode, String divisionCode, Integer year, String orgId) {
        // 获取行政区划
        this.idtMonitorValueService.getNameByDivisionCode(divisionCode);
        //获取根据编码获取体系类型--默认上一年作为体系年份
        IdtIndicatorsType one = iIdtIndicatorsTypeService.findByCode(indicatorsTypeCode, year+"", divisionCode);
        //获取父节点下的所有数据
        List<ApiIdtIndicatorsDir> indicatorsDirList = idtIndicatorsDirService.listDirByCode(one.getId(), null,null);
        // 排序
        indicatorsDirList = SortUtil.sortList(indicatorsDirList, one.getId(), 1);
        // 查指标数值
        indicatorsDirList.parallelStream().forEach((idtDir)->{
            if(idtDir.getType()==2){
                // 单年份指标数值
                ApiIndicatorsVal apiIndicatorsVal = iIdtIndicatorsService.getIdtVal(idtDir.getIndicatorsId(), String.valueOf(year), divisionCode, false,false);
                apiIndicatorsVal.setValue(this.holdTwoDecimal(apiIndicatorsVal.getValue()));
                apiIndicatorsVal.setTargetValue(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue()));
                apiIndicatorsVal.setBaseValue(this.holdTwoDecimal(apiIndicatorsVal.getBaseValue()));
                apiIndicatorsVal.setMonitorValue(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue()));
                idtDir.setApiIndicatorsVal(apiIndicatorsVal);
            }
        });
        String docxFileUrl = null;
        // word文档
        String docxName = null;
        try {
            docxName = this.exportMonitorWarningReportWord(indicatorsDirList, divisionCode, year);
        } catch (Exception e) {
            e.printStackTrace();
        }
        docxFileUrl = FileUtil.tempFilePath + docxName;

        return docxFileUrl;
    }

    /**
     * @描述: 导出【国土空间规划监测评估预警报告】到本地
     * @入参: indicatorsDirList 指标目录列表
     * @入参: divisionCode 行政区划码
     * @入参: year 年份
     * @出参: 【国土空间规划监测评估预警报告】本地临时文件名
     * @作者: 陈宏成
     * @日期: 2021/01/20
     **/
    private String exportMonitorWarningReportWord(List<ApiIdtIndicatorsDir> indicatorsDirList, String divisionCode, Integer year ) throws Exception {
        // 行政区划
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        // 统计指标数
        long idtNum = indicatorsDirList.stream().filter(dir -> dir.getType() == 2).count();
        // 类型为指标 + 预警状态存在 + 包含‘预警’二字
        long warningIdtNum = indicatorsDirList.stream().filter(dir -> {
            return dir.getType() == 2 && dir.getApiIndicatorsVal() != null && StringUtils.hasText(dir.getApiIndicatorsVal().getWarnStatus())
            && dir.getApiIndicatorsVal().getWarnStatus().contains("预警");
        }).count();
        // 文档域字段
        List<Map<String, Object>> fieldData = new ArrayList<>(2);
        HashMap<String, Object> docFieldMap = new HashMap<>();
        HashMap<String, Object> docHtmlFieldMap = new HashMap<>();
        fieldData.add(docFieldMap);
        fieldData.add(docHtmlFieldMap);
        // 普通文档域字段
        ArrayList<Object> fieldList = new ArrayList<>();
        HashMap<String, Object> fieldMap = new HashMap<>();
        fieldMap.put("XZQ",divisionText == null? "":divisionText);
        fieldMap.put("NF",year);
        fieldMap.put("ZBS",idtNum);
        fieldMap.put("YJZBS",warningIdtNum);
        fieldList.add(fieldMap);
        docFieldMap.put("table",fieldList);
        // 文档表格字段
        List<Map<String, Object>> tableDataList = new ArrayList<>();
        // 处理表格数据
        // 抽取指标项
        List<ApiIdtIndicatorsDir> indicatorsList = indicatorsDirList.stream().filter(dir -> dir.getType() == 2).collect(Collectors.toList());
        // 抽取目录项
        List<ApiIdtIndicatorsDir> dirList = indicatorsDirList.stream().filter(dir -> dir.getType() == 1).collect(Collectors.toList());
        // 遍历指标项
        for(int i = 0; i < indicatorsList.size(); i++) {
            ApiIdtIndicatorsDir indicators = indicatorsList.get(i);
            Map<String, Object> rowDataMap = new HashMap<>(10);
            rowDataMap.put("XH",i+1);
            rowDataMap.put("JCZ",indicators.getApiIndicatorsVal().getMonitorYear()==null?"":indicators.getApiIndicatorsVal().getMonitorValue());
            rowDataMap.put("GHZ",indicators.getApiIndicatorsVal().getTargetYear()==null?"":indicators.getApiIndicatorsVal().getTargetValue());
            if(StringUtils.hasText(indicators.getApiIndicatorsVal().getMonitorYear()) && StringUtils.hasText(indicators.getApiIndicatorsVal().getTargetYear())
                    && StringUtils.hasText(indicators.getApiIndicatorsVal().getMonitorValue()) && StringUtils.hasText(indicators.getApiIndicatorsVal().getTargetValue()) ){
                Double diffValue = this.iIdtIndicatorsService.countDiffValue(indicators.getApiIndicatorsVal().getWarnRule(), indicators.getApiIndicatorsVal().getMonitorValue()
                    , indicators.getApiIndicatorsVal().getTargetValue());
                rowDataMap.put("CZ",diffValue == null? "":diffValue);
            }else{
                rowDataMap.put("CZ","");
            }
            rowDataMap.put("DW",indicators.getIdtUnit()==null?"":indicators.getIdtUnit());
            String warnStatus = indicators.getApiIndicatorsVal().getWarnStatus();
            rowDataMap.put("YJZT",warnStatus);
            // 寻找当前指标的上级目录
            String[] titleFields = {"YJML","EJML","SJML","ZBMC"};
            List<String> titleValues = new LinkedList<>();
            titleValues.add(indicators.getIdtName() == null ? "" : indicators.getIdtName() );
            StringBuilder parentId = new StringBuilder(indicators.getParentId());
            // 寻找上级目录
            while(true){
                ApiIdtIndicatorsDir parentDir = dirList.stream().filter(dir -> dir.getId().equals(parentId.toString())).findAny().orElse(null);
                if(parentDir == null){
                    break;
                }else{
                    titleValues.add(0,parentDir.getName());
                    parentId.delete(0,parentId.length());
                    parentId.append(parentDir.getParentId());
                }
            }
            // 将上级目录放入map
            for(int j = 0,titleValuesIndex = 0; j < titleFields.length; j++, titleValuesIndex++) {
                String titleField = titleFields[j];
                if(titleValuesIndex < titleValues.size()){
                    rowDataMap.put(titleField, titleValues.get(titleValuesIndex));
                }else{
                    rowDataMap.put(titleField, null);
                }
            }
            tableDataList.add(rowDataMap);
        }

        // 处理竖向单元格合并，一级目录，二级目录
        List<Map<String, String>> mergeTableCellList = this.buildMergeCells(new String[][]{{"YJML", "1"}, {"EJML", "2"}, {"SJML", "3"}, {"ZBMC", "4"}},  tableDataList, 1);

        // 构建表格html
        StringBuilder htmlTableBuilder = new StringBuilder();
        htmlTableBuilder.append("<table style =\"border-collapse:collapse;border: solid 1px #000;font-family:'宋体';\">");
        htmlTableBuilder.append("<tr><td>序号</td>");
        htmlTableBuilder.append("<td colspan=\"4\">指标名称</td>");
        htmlTableBuilder.append("<td>监测值</td>");
        htmlTableBuilder.append("<td>规划值</td>");
        htmlTableBuilder.append("<td>差值</td>");
        htmlTableBuilder.append("<td>单位</td>");
        htmlTableBuilder.append("<td>预警状态</td></tr>");
        int index = 1;
        List<List<Object>> htmlTableList = new LinkedList<>();
        for(Map<String, Object> stringObjectMap : tableDataList) {
            List<Object> trList = new LinkedList<>();
            htmlTableList.add(trList);
            trList.add( stringObjectMap.get("XH") );
            trList.add( stringObjectMap.get("YJML") );
            trList.add( stringObjectMap.get("EJML") );
            trList.add( stringObjectMap.get("SJML") );
            trList.add( stringObjectMap.get("ZBMC") );
            trList.add( stringObjectMap.get("JCZ") );
            trList.add( stringObjectMap.get("GHZ") );
            trList.add( stringObjectMap.get("CZ") );
            trList.add( stringObjectMap.get("DW") );
            trList.add( stringObjectMap.get("YJZT") );
        }
        // 预警状态字段下标
        int warnStatusIndex = 9;
        for(int rowIndex = 0; rowIndex < htmlTableList.size(); rowIndex++) {
            List<Object> trList = htmlTableList.get(rowIndex);
            htmlTableBuilder.append("<tr>");
            for(int colIndex = 0; colIndex < trList.size(); colIndex++) {
                String cellValue = trList.get(colIndex) == null ? "": trList.get(colIndex).toString();
                // 单元格样式，只有预警状态才有
                String style = "";
                if (colIndex == warnStatusIndex){
                    if (cellValue.indexOf(",") != -1){
                        String[] split = cellValue.split(",");
                        style = split[0];
                        cellValue = split[1];
                    }
                    if (!"".equals(style)){
                        if ("null".equals(style)){
                            style = "style=\"color:#ffffff; background: #dcdfe6;\"";
                        }else {
                            style = "style=\"color:#ffffff; background: " + style + " ;\"";
                        }
                    }
                }

                // 处理合并单元格
                String cellValueTd = "<td " + style + ">" + cellValue + "</td>";
                for(Map<String, String> stringStringMap : mergeTableCellList) {
                    String rowCell = stringStringMap.get("rowCell");
                    String[] split = rowCell.split(",");
                    int rowStart = Integer.parseInt(split[0]) - 1;
                    int colStart = Integer.parseInt(split[1]);
                    int rowEnd = Integer.parseInt(split[2]) - 1;
                    int colEnd = Integer.parseInt(split[3]);
                    if (rowIndex == rowStart && colIndex == colStart){
                        cellValueTd = "<td rowspan=\"" + (rowEnd - rowStart + 1) + "\" colspan=\"" + (colEnd - colStart + 1) + "\" " + style + ">" + cellValue + "</td>";
                    }else if(rowIndex <= rowEnd && colIndex <= colEnd && rowIndex >= rowStart && colIndex >= colStart){
                        cellValueTd = "";
                    }
                }
                htmlTableBuilder.append(cellValueTd);
            }
            htmlTableBuilder.append("</tr>");
        }
        htmlTableBuilder.append("</table>");

        // 文档的html字段
        docHtmlFieldMap.put("type","html");
        List<Map<String, String>> htmlStrList = new ArrayList<>(1);
        docHtmlFieldMap.put("table",htmlStrList);
        HashMap<String, String> htmlStrMap = new HashMap<>(1);
        htmlStrList.add(htmlStrMap);
        // 抽取预警指标
        indicatorsDirList = indicatorsDirList.stream().filter(dir->{
            if (dir.getType()==2){
                return dir.getApiIndicatorsVal() != null && StringUtils.hasText(dir.getApiIndicatorsVal().getWarnStatus()) && dir.getApiIndicatorsVal().getWarnStatus().contains("预警");
            }
            return false;
        }).collect(Collectors.toList());
        // 遍历
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("divisionCode",divisionCode);
        dataMap.put("divisionText",divisionText);
        dataMap.put("year",year);
        dataMap.put("imgNum",0);
        dataMap.put("tableNum",0);
        // 构建第二部分的内容
        StringBuilder stringBuilder = new StringBuilder("");
        int itemNum = 0;
        for(ApiIdtIndicatorsDir idtIndicatorsDir : indicatorsDirList) {
            String htmlStr = this.buildMonitorWarningReportWordHtml(idtIndicatorsDir, dataMap);
            if(org.apache.commons.lang.StringUtils.isNotBlank(htmlStr)){
                stringBuilder.append("<h2 style=\"font-family:'宋体';font-size:18px;\">").append(++itemNum).append(". ").append(idtIndicatorsDir.getIdtName()).append("</h2>");
                stringBuilder.append(htmlStr);
            }
        }
        if(stringBuilder.length() > 0){
            stringBuilder.insert(0,"<h1 style=\"font-family:'宋体';font-size:18px;\">二、预警指标详情</h1>");
        }
        stringBuilder.insert(0,"<style>table,td,th{font-size:12px;border:1px solid grey;padding:5px;width:555px;text-align:center;}p,span,h1,h2,h3,div{font-family:'宋体';}*{font-family:'宋体';}</style>");
        // 处理html图片的预留埋点
        Map<String,String> echartOptions = (Map<String,String>)dataMap.getOrDefault("echartOptions", new HashMap<>());
        this.replaceEchartImgForHtml(echartOptions,stringBuilder);

        htmlStrMap.put("html_str",htmlTableBuilder.toString() + stringBuilder.toString());
        // 加载模板文件
        ClassPathResource resource = new ClassPathResource("template/【监测预警】及时预警报告模板.docx");
        InputStream inputStream = resource.getInputStream();
        //进行word打印
//        String docx = NewWordUtil.wordprint(inputStream, fieldData, tableData, null, "docx", "", "", mergeTableList);
        String docx = NewWordUtil.wordprint(inputStream, fieldData, null, null, "docx", "", "", null);
        inputStream.close();
        return docx.substring(docx.lastIndexOf("/") + 1, docx.length());
    }


    /***
     * 将html中预留的echars图片埋点全部替换成图片base64，注意：html中的埋点为以下格式： <img data-id="id">  。id值可以使模型id，也可以是其他的唯一id，要和 echartOptions 参数中的 key 能对应上。
     * @入参: echartOptions echarts的option完整配置，已经装填好数据的那种，key为埋点<img data-id="id">的id的值
     * @入参: stringBuilder html字符串
     * @出参: 图片替换成base64后的html
     * @作者: 陈宏成
     * @日期: 2021/02/04
     */
    private StringBuilder replaceEchartImgForHtml(Map<String,String> echartOptions, StringBuilder stringBuilder){
        if (echartOptions.isEmpty()){
            return stringBuilder;
        }
        echartOptions.entrySet().parallelStream().forEach(entry->{
            String id = entry.getKey();
            String option = entry.getValue();
            String base64Str = null;
            try {
                String eChartPath = EchartGenerateUtil.generateEChart(option);
                base64Str = ByteToFileUtils.encodeBase64File(eChartPath);
                //删除文件
                FileUtil.deleteFile(eChartPath);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 如果图片存在，替换html埋点
                String imgHtml = "";
                if (StringUtils.hasText(base64Str)){
                    imgHtml = "<img style=\"text-align:center;display:table-cell\" src=\"data:image/png;base64," + base64Str + "\">";
                }
                String imgBuriedPointStr  = "<img data-id=\"" + id + "\">";
                synchronized (stringBuilder){
                    int imgIndexStart = stringBuilder.indexOf(imgBuriedPointStr);
                    int imgIndexend = imgIndexStart + imgBuriedPointStr.length();
                    stringBuilder.replace(imgIndexStart,imgIndexend,imgHtml);
                }
            }
        });
        return stringBuilder;
    }

    /**
     * @描述: 构建合并html
     * @入参: indicatorsDir 指标
     * @入参: dataMap 数据参数
     * @出参: html字符串
     * @作者: 陈宏成
     * @日期: 2021/01/20
     **/
    private String buildMonitorWarningReportWordHtml(ApiIdtIndicatorsDir indicatorsDir, Map<String, Object> dataMap){
        StringBuilder stringBuilder = new StringBuilder("");
        String divisionCode = (String)dataMap.get("divisionCode");
        String divisionText = (String) dataMap.get("divisionText");
        Integer year = (Integer) dataMap.get("year");
        // 查询当前行政区子级行政区
        List<ApiMapDivision> apiMapDivisions = idtMonitorValueService.listDirectChildDivision(divisionCode);
        // 查询当前行政区子级行政区的指标数值
        String subDivisionCodes = apiMapDivisions.stream().map(ApiMapDivision::getCode).collect(Collectors.joining(","));
        List<ApiIndicatorsVal> subDivisionIndicatorsValList = iIdtIndicatorsService.listSingleIdtVal(indicatorsDir.getIndicatorsId(),year+"",subDivisionCodes,false,false);
        subDivisionIndicatorsValList.stream().forEach(val->{
            Optional<ApiMapDivision> mapDivision = apiMapDivisions.stream().filter(division -> division.getCode().equals(val.getDivisionCode())).findAny();
            val.setDivisionName(mapDivision.isPresent()? mapDivision.get().getName(): "");
            val.setValue(this.holdTwoDecimal(val.getValue()));
            val.setTargetValue(this.holdTwoDecimal(val.getTargetValue()));
            val.setBaseValue(this.holdTwoDecimal(val.getBaseValue()));
            val.setMonitorValue(this.holdTwoDecimal(val.getMonitorValue()));
        });
        // 查询该指标近四年的指标值
        List<ApiIndicatorsVal> nearFourYearIndicatorsVals = iIdtIndicatorsService.listSingleIdtVal(indicatorsDir.getIndicatorsId(),(year - 3)+","+(year - 2)+","+(year - 1)+","+year,divisionCode,false,false);
        // 构建文本说明
        stringBuilder.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">")
                .append(divisionText).append(year).append("年")
                .append(indicatorsDir.getIdtName()).append("监测值为")
                .append(indicatorsDir.getApiIndicatorsVal().getMonitorValue())
                .append(indicatorsDir.getIdtUnit()==null?"":indicatorsDir.getIdtUnit()).append("，")
                .append(org.apache.commons.lang.StringUtils.isNotBlank(indicatorsDir.getApiIndicatorsVal().getTargetYear())?indicatorsDir.getApiIndicatorsVal().getTargetYear():"-").append("年规划值为")
                .append(org.apache.commons.lang.StringUtils.isNotBlank(indicatorsDir.getApiIndicatorsVal().getTargetYear())?indicatorsDir.getApiIndicatorsVal().getTargetValue():"-")
                .append(indicatorsDir.getIdtUnit()==null?"":indicatorsDir.getIdtUnit())
                .append("，指标出现预警。");
        // 统计预警的下级行政区域
        String warningDivisions = subDivisionIndicatorsValList.stream().filter(val -> {
            return StringUtils.hasText(val.getWarnStatus()) && val.getWarnStatus().contains("预警");
        }).map(ApiIndicatorsVal::getDivisionName).collect(Collectors.joining("，"));
        if (StringUtils.hasText(warningDivisions)){
            stringBuilder.append(divisionText).append("下辖行政区划中，").append(warningDivisions).append("出现预警状态。");
        }
        stringBuilder.append("具体情况如下：");
        // 构建echart图表
        // 获取option配置文件内容
        String option = (String) dataMap.get( "chartOptionFtlStr" );
        if (!StringUtils.hasText(option)){
            ClassPathResource resource = new ClassPathResource("template/option.ftl" );
            try {
                InputStream inputStream = resource.getInputStream();
                option = FileUtil.txt2String(inputStream, "utf-8");
            }catch (Exception e){
                throw new RuntimeException("加载option.ftl文件失败", e);
            }
            dataMap.put("chartOptionFtlStr", option);
        }
        option = option.replace("${recentYear}",JSON.toJSONString(Arrays.asList(year-3,year-2,year-1,year)));
        option = option.replace("${unit}",indicatorsDir.getIdtUnit()==null?"":indicatorsDir.getIdtUnit());
        option = option.replace("${monitorValue}",JSON.toJSONString(nearFourYearIndicatorsVals.stream().map(ApiIndicatorsVal::getMonitorValue).collect(Collectors.toList())));
        option = option.replace("${targetValue}",JSON.toJSONString(nearFourYearIndicatorsVals.stream().map(ApiIndicatorsVal::getTargetValue).collect(Collectors.toList())));
        // 将图表结果暂存
        Map<String,String> echartOptions = (Map<String,String>)dataMap.get("echartOptions");
        if (echartOptions == null){
            echartOptions = new HashMap<>();
            dataMap.put("echartOptions",echartOptions);
        }
        echartOptions.put(indicatorsDir.getIndicatorsId(), option);
        // 在html中预留埋点，方便后面直接替换
        stringBuilder.append("<img data-id=\"").append(indicatorsDir.getIndicatorsId()).append("\">");

        // 表格序号
        Integer tableNum = (Integer)dataMap.get("tableNum") + 1;
        dataMap.put("tableNum",tableNum);
        // 构建子行政区域的表格
        stringBuilder.append("<p style=\"text-align:center;font-family:'宋体';\">表2-").append(tableNum).append(indicatorsDir.getIdtName()).append("区域情况</p>\n")
                .append("<table style =\"border-collapse:collapse;border: solid 1px #000;font-family:'宋体';\">")
                .append("<tr><td>序号</td><td>行政区</td><td>监测值</td><td>规划值").append(indicatorsDir.getApiIndicatorsVal().getTargetYear()==null?"":"("+indicatorsDir.getApiIndicatorsVal().getTargetYear()+"年)").append("</td><td>预警状态</td></tr>");
        for(int i = 0; i < subDivisionIndicatorsValList.size(); i++) {
            ApiIndicatorsVal apiIndicatorsVal = subDivisionIndicatorsValList.get(i);
            stringBuilder.append("<tr>")
                    .append("<td>").append(i+1).append("</td>")
                    .append("<td>").append(apiIndicatorsVal.getDivisionName()).append("</td>")
                    .append("<td>").append(apiIndicatorsVal.getMonitorValue() == null? "":apiIndicatorsVal.getMonitorValue()).append("</td>")
                    .append("<td>").append(apiIndicatorsVal.getTargetValue() == null? "":apiIndicatorsVal.getTargetValue()).append("</td>");
            String warnStatus = apiIndicatorsVal.getWarnStatus();
            if (!StringUtils.hasText(warnStatus)){
                stringBuilder.append("<td>").append("</td></tr>");
            }else{
                String[] split = warnStatus.split(",");
                String color = split[0];
                warnStatus = split[1];
                if("null".equals(color)){
                    stringBuilder.append("<td style=\"color:" + "#ffffff" + ";background: " + "#dcdfe6" + " ;\">").append(warnStatus).append("</td></tr>");
                }else{
                    stringBuilder.append("<td style=\"color:" + "#ffffff" + ";background: " + color + " ;\">").append(warnStatus).append("</td></tr>");
                }
            }
        }
        stringBuilder.append("</table>");
        return stringBuilder.toString();
    }

    /**
     * @描述: 导出【监测评估报告】word
     * @作者: 陈宏成
     * @日期: 2021/01/14
     **/
    @Override
    public void exportMonitorValue(HttpServletResponse response, String code, String divisionCode, Integer year, String orgId, String particularYear) {
        //获取根据编码获取体系类型
        IdtIndicatorsType iIdtIndicatorsType = iIdtIndicatorsTypeService.findByCode(code, particularYear, divisionCode);
        //获取父节点下的所有数据
        List<ApiIdtIndicatorsDir> listData = idtIndicatorsDirService.listDirByCode(iIdtIndicatorsType.getId(), orgId, null);
        // 排序
        listData = SortUtil.sortList(listData, iIdtIndicatorsType.getId(), 1);
        // 查指标数值
        if (listData != null && listData.size() > 0) {
            listData.parallelStream().forEach(idtDir -> {
                if (idtDir.getType() == 2) {
                    ApiIndicatorsVal apiIndicatorsVal = iIdtIndicatorsService.getIdtVal(idtDir.getIndicatorsId(), String.valueOf(year), divisionCode, false, false);
                    apiIndicatorsVal.setValue(this.holdTwoDecimal(apiIndicatorsVal.getValue()));
                    apiIndicatorsVal.setTargetValue(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue()));
                    apiIndicatorsVal.setBaseValue(this.holdTwoDecimal(apiIndicatorsVal.getBaseValue()));
                    apiIndicatorsVal.setMonitorValue(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue()));
                    idtDir.setApiIndicatorsVal(apiIndicatorsVal);
                }
            });
        }
        String docxFileUrl = null;
        try{
            // word文档
            String docxName = this.exportMonitorValueWord(listData, divisionCode, year);
            docxFileUrl = FileUtil.tempFilePath + docxName;
            // 文件名
            String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
            String newExportFileName = divisionText+"国土空间规划监测评估报告（"+ String.valueOf(year) +"年）" ;
            // 导出
            InputStream inputStream = new FileInputStream(docxFileUrl);
            response.setContentType("application/octet-stream;charset=UTF-8;");
            response.setHeader("Content-Disposition", "attachment; filename=\"" +  new String(newExportFileName.getBytes(),"iso-8859-1") + ".docx"+ "\"");
            ServletOutputStream outputStream = response.getOutputStream();
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(bytes)) > 0){
                outputStream.write(bytes,0,len);
            }
            inputStream.close();
            outputStream.flush();
            outputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(docxFileUrl != null){
                FileUtil.deleteFile(docxFileUrl);
            }
        }
    }

    /**
     * @描述: 生成监测值报告word文档，保存到本地磁盘
     * @入参: listData 指标数据，包括目录和指标，按照指标目录树的结构排序
     * @入参: divisionCode 行政区划码
     * @入参: year 年份
     * @出参: 生成的监测值报告word文档的本地文件名
     * @作者: 陈宏成
     * @日期: 2021/01/14
     **/
    private String exportMonitorValueWord(List<ApiIdtIndicatorsDir> listData, String divisionCode, int year) throws Exception {
        //获取行政区划文本名称
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        // 文档域字段
        List<Map<String, Object>> fieldData = new ArrayList<>(2);
        HashMap<String, Object> docFieldMap = new HashMap<>();
        HashMap<String, Object> docHtmlFieldMap = new HashMap<>();
        fieldData.add(docFieldMap);
        fieldData.add(docHtmlFieldMap);
        // 普通文档域字段
        ArrayList<Object> fieldList = new ArrayList<>();
        HashMap<String, Object> fieldMap = new HashMap<>();
        fieldMap.put("XZQ",divisionText == null? "":divisionText);
        fieldMap.put("NF",year);
        fieldList.add(fieldMap);
        docFieldMap.put("table",fieldList);
        // 表格文档字段
        List<Map<String, Object>> tableData = new ArrayList<>();
        HashMap<String, Object> tableDataMap = new HashMap<>();
        tableData.add(tableDataMap);
        tableDataMap.put("name","ZBMX");
        List<Map<String, Object>> tableDataList = new ArrayList<>();
        tableDataMap.put("table",tableDataList);
        // 抽取出指标
        List<ApiIdtIndicatorsDir> apiIdtIndicatorList = new ArrayList<>();
        for(ApiIdtIndicatorsDir apiIdtIndicator : listData) {
            if(apiIdtIndicator.getType() == 2){
                apiIdtIndicatorList.add(apiIdtIndicator);
            }
        }
        fieldMap.put("ZBS",apiIdtIndicatorList.size());
        // 抽取出目录
        List<ApiIdtIndicatorsDir> dirList = listData.stream().filter(dir -> dir.getType() == 1).collect(Collectors.toList());
        // 整理表格数据
        int warningIdtIndicatorNum = 0;
        for(int i = 0; i < apiIdtIndicatorList.size(); i++) {
            ApiIdtIndicatorsDir apiIdtIndicatorsDir = apiIdtIndicatorList.get(i);
            Map<String, Object> stringObjectHashMap = new HashMap<>(9);
            stringObjectHashMap.put("XH",i+1);
            stringObjectHashMap.put("JCZ",apiIdtIndicatorsDir.getApiIndicatorsVal().getMonitorValue());
            stringObjectHashMap.put("JQZ",apiIdtIndicatorsDir.getApiIndicatorsVal().getBaseValue());
            stringObjectHashMap.put("GHZ",apiIdtIndicatorsDir.getApiIndicatorsVal().getTargetValue());
            stringObjectHashMap.put("DW",apiIdtIndicatorsDir.getIdtUnit());
            if("预警".equals(apiIdtIndicatorsDir.getApiIndicatorsVal().getWarnStatus())){
                stringObjectHashMap.put("YJ",apiIdtIndicatorsDir.getApiIndicatorsVal().getWarnStatus());
                stringObjectHashMap.put("ZC","");
                warningIdtIndicatorNum++;
            }else if ("正常".equals(apiIdtIndicatorsDir.getApiIndicatorsVal().getWarnStatus())){
                stringObjectHashMap.put("YJ","");
                stringObjectHashMap.put("ZC",apiIdtIndicatorsDir.getApiIndicatorsVal().getWarnStatus());
            }else{
                stringObjectHashMap.put("ZC","");
                stringObjectHashMap.put("YJ","");
            }
            // 寻找当前指标的上级目录
            String[] titleFields = {"YJML","EJML","SJML","ZBMC"};
            List<String> titleValues = new LinkedList<>();
            titleValues.add(apiIdtIndicatorsDir.getIdtName() == null ? "" : apiIdtIndicatorsDir.getIdtName() );
            StringBuilder parentId = new StringBuilder(apiIdtIndicatorsDir.getParentId());
            // 寻找上级目录
            while(true){
                ApiIdtIndicatorsDir parentDir = dirList.stream().filter(dir -> dir.getId().equals(parentId.toString())).findAny().orElse(null);
                if(parentDir == null){
                    break;
                }else{
                    titleValues.add(0,parentDir.getName());
                    parentId.delete(0,parentId.length());
                    parentId.append(parentDir.getParentId());
                }
            }
            // 将上级目录放入map
            for(int j = 0,titleValuesIndex = 0; j < titleFields.length; j++, titleValuesIndex++) {
                String titleField = titleFields[j];
                if(titleValuesIndex < titleValues.size()){
                    stringObjectHashMap.put(titleField, titleValues.get(titleValuesIndex));
                }else{
                    stringObjectHashMap.put(titleField, null);
                }
            }
            tableDataList.add(stringObjectHashMap);
        }
        fieldMap.put("YJZBS",warningIdtIndicatorNum);
        // 整理合并单元格数据
        List<Map<String, Object>> mergeTableList = new ArrayList<>(1);
        HashMap<String, Object> mergeTableMap = new HashMap<>(2);
        mergeTableList.add(mergeTableMap);
        mergeTableMap.put("xh",0);
        List<Map<String, String>> mergeTableCellList = this.buildMergeCells(new String[][]{{"YJML", "1"}, {"EJML", "2"}, {"SJML", "3"}, {"ZBMC", "4"}},  tableDataList, 1);
        mergeTableMap.put("cells",mergeTableCellList);
        // 拼接文档第二部分内容：预警指标详情
        // 抽取出预警状态的指标
        List<ApiIdtIndicatorsDir> warningIdtList = apiIdtIndicatorList.stream().filter(idt -> "预警".equals(idt.getApiIndicatorsVal().getWarnStatus())).collect(Collectors.toList());
        docHtmlFieldMap.put("type","html");
        List<Map<String, String>> htmlStrList = new ArrayList<>(1);
        docHtmlFieldMap.put("table",htmlStrList);
        HashMap<String, String> htmlStrMap = new HashMap<>(1);
        htmlStrList.add(htmlStrMap);
        // 拼接html文本
        StringBuilder stringBuilder = new StringBuilder("");
        if (warningIdtList != null && !warningIdtList.isEmpty()){
            // 拼接html文本
            stringBuilder = new StringBuilder();
            stringBuilder.append("<style>table,td,th{font-size:12px;border:1px solid grey;padding:5px;width:555px;text-align:center;}p,span,h1,h2,h3,div{font-family:'宋体';}*{font-family:'宋体';}</style>");
            stringBuilder.append("<h2 style=\"font-family:'宋体';font-size:18px;\">二、预警指标详情</h2>\n");
            for(int i = 0; i < warningIdtList.size(); i++) {
                ApiIdtIndicatorsDir apiIdtIndicatorsDir = warningIdtList.get(i);
                ApiIndicatorsVal apiIndicatorsVal1 = apiIdtIndicatorsDir.getApiIndicatorsVal();
                stringBuilder.append("<h3 style=\"font-family:'宋体';font-size:18px;\">").append(i+1).append(". ").append(apiIdtIndicatorsDir.getIdtName()).append("</h3>\n").append("<p  style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">")
                        .append(divisionText).append(this.convertNullStringToLine(apiIndicatorsVal1.getMonitorYear()," - ")).append("年")
                        .append(apiIdtIndicatorsDir.getIdtName()).append("监测值为")
                        .append(this.convertNullStringToLine(apiIndicatorsVal1.getMonitorValue()," - ")).append(apiIdtIndicatorsDir.getIdtUnit()).append("，")
                        .append(this.convertNullStringToLine(apiIndicatorsVal1.getBaseYear()," - ")).append("年基期值为")
                        .append(this.convertNullStringToLine(apiIndicatorsVal1.getBaseValue()," - ")).append(apiIdtIndicatorsDir.getIdtUnit()).append("，")
                        .append(this.convertNullStringToLine(apiIndicatorsVal1.getTargetYear()," - ")).append("年规划值为")
                        .append(this.convertNullStringToLine(apiIndicatorsVal1.getTargetValue()," - ")).append(apiIdtIndicatorsDir.getIdtUnit()).append("，")
                        .append("指标出现预警。");
                // 查询这个地区的直接下级地区
                List<ApiMapDivision> directChildDivision = idtMonitorValueService.listDirectChildDivision(divisionCode);
                // 这个地区的直接下级地区的数值情况
                List<ApiIndicatorsVal> directChildDivisionIndicatorsVals = null;
                if (directChildDivision != null && !directChildDivision.isEmpty()){
                    String divisionCodeListStr = directChildDivision.stream().map(ApiMapDivision::getCode).collect(Collectors.joining(","));
                    directChildDivisionIndicatorsVals = iIdtIndicatorsService.listSingleIdtVal(apiIdtIndicatorsDir.getIndicatorsId(), String.valueOf(year), divisionCodeListStr,false, false);
                    // 获取地区中文名
                    directChildDivisionIndicatorsVals.stream().forEach(idt->{
                        idt.setDivisionName(idtMonitorValueService.getNameByDivisionCode(idt.getDivisionCode()));
                    });
                    // 获取预警状态的下级区域
                    String warningDirectChildDivision = directChildDivisionIndicatorsVals.stream().filter(val -> "预警".equals(val.getWarnStatus())).map(ApiIndicatorsVal::getDivisionName).collect(Collectors.joining("，"));
                    if (StringUtils.hasText(warningDirectChildDivision)){
                        stringBuilder.append(divisionText).append("下辖行政区划中，").append(warningDirectChildDivision).append("出现预警状态，");
                    }
                }
                stringBuilder.append("具体情况如下：</p>");
                // 查询当前地区进四年的指标值情况，并生成echarts图表
                List<ApiIndicatorsVal> apiIndicatorsVals = iIdtIndicatorsService.listRangeIdtVal(apiIdtIndicatorsDir.getIndicatorsId(), String.valueOf(year - 3), String.valueOf(year), divisionCode,false, false);
                //生成echart图片
                HashMap<String, Object> datas = new HashMap<>();
                datas.put("recentYear", JSON.toJSONString(Arrays.asList(year-3,year-2,year-1,year)));
                datas.put("unit", apiIdtIndicatorsDir.getIdtUnit());
                datas.put("monitorValue", JSON.toJSONString(apiIndicatorsVals.stream().map(ApiIndicatorsVal::getMonitorValue).collect(Collectors.toList())));
                datas.put("targetValue", JSON.toJSONString(apiIndicatorsVals.stream().map(ApiIndicatorsVal::getTargetValue).collect(Collectors.toList())));
                datas.put("ftl", "option.ftl");
                try {
                    String option = FreemarkerUtil.generateString((String) datas.get("ftl"), "/template", datas);
                    String eChartPath = EchartGenerateUtil.generateEChart(option);
                    String base64Str = ByteToFileUtils.encodeBase64File(eChartPath);
                    //删除文件
                    FileUtil.deleteFile(eChartPath);
                    stringBuilder.append("<img style=\"text-align:center;display:table-cell\" src=\"data:image/png;base64,").append(base64Str).append("\">")
                            .append("<p style=\"text-align:center;font-family:'宋体';\">图2-").append(i+1).append(apiIdtIndicatorsDir.getIdtName()).append("历年变化</p>\n");
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 生成该地区直接子级地区的数值情况
                if (directChildDivisionIndicatorsVals != null && !directChildDivisionIndicatorsVals.isEmpty()){
                    stringBuilder.append("<p style=\"text-align:center;font-family:'宋体';\">表2-").append(i+1).append(apiIdtIndicatorsDir.getIdtName()).append("区域情况</p>")
                            .append("<table style =\"border-collapse:collapse;border: solid 1px #000;font-family:'宋体';\">")
                            .append("<tr><td>序号</td><td>行政区</td><td>监测值</td><td>规划值").append(apiIdtIndicatorsDir.getApiIndicatorsVal().getTargetYear()==null?"":"("+apiIdtIndicatorsDir.getApiIndicatorsVal().getTargetYear()+")").append("</td><td>预警状态</td></tr>");
                    for(int i1 = 0; i1 < directChildDivisionIndicatorsVals.size(); i1++) {
                        ApiIndicatorsVal apiIndicatorsVal = directChildDivisionIndicatorsVals.get(i1);
                        stringBuilder.append("<tr>").append("<td>").append(i1+1).append("</td>")
                                .append("<td>").append(apiIndicatorsVal.getDivisionName()).append("</td>")
                                .append("<td>").append(this.holdTwoDecimal(apiIndicatorsVal.getMonitorValue())).append("</td>")
                                .append("<td>").append(this.holdTwoDecimal(apiIndicatorsVal.getTargetValue())).append("</td>");
                        if ("预警".equals(apiIndicatorsVal.getWarnStatus())){
                            stringBuilder.append("<td style=\"color:#f93e3e;\">").append(apiIndicatorsVal.getWarnStatus()).append("</td></tr>");
                        }else if ("正常".equals(apiIndicatorsVal.getWarnStatus())){
                            stringBuilder.append("<td style=\"color:#49cc90;\">").append(apiIndicatorsVal.getWarnStatus()).append("</td></tr>");
                        }else{
                            stringBuilder.append("<td>").append("</td></tr>");
                        }
                    }
                    stringBuilder.append("</table>");
                }
            }
        }
        htmlStrMap.put("html_str",stringBuilder.toString());
        // 加载模板文件
        ClassPathResource resource = new ClassPathResource("template/【监测预警】监测数值报告模板.docx");
        InputStream inputStream = resource.getInputStream();
        //进行word打印
        String docx = NewWordUtil.wordprint(inputStream, fieldData, tableData, null, "docx", "", "", mergeTableList);
        inputStream.close();
        return docx.substring(docx.lastIndexOf("/") + 1, docx.length());
    }

    /**
     * @描述: 构建合并单元格
     * @入参: mergeFields 合并单元格字段配置，{{"列字段名称","列字段下标，从0开始"},{"YJML", "1"}, {"EJML", "2"}, {"SJML", "3"}, {"ZBMC", "4"}}
     * @入参: tableDataList 数据列表
     * @入参: dataRowStartIndex 数据列开始行的下标
     * @出参: 合并单元格
     * @作者: 陈宏成
     * @日期: 2021/01/20
     **/
    private List<Map<String, String>> buildMergeCells(String[][] mergeFields, List<Map<String, Object>> tableDataList, int dataRowStartIndex){
        List<Map<String, String>> mergeTableCellList = new ArrayList<>();
        int rowStart = 0, rowEnd = 0, colStart = 0, colEnd = 0;
        // 每列纵向合并
        for(String[] mergeField : mergeFields) {
            rowStart = dataRowStartIndex;
            rowEnd = dataRowStartIndex;
            colStart = Integer.valueOf(mergeField[1]);
            colEnd = Integer.valueOf(mergeField[1]);
            // 遍历所有行
            String title = null;
            for(int i = 0; i < tableDataList.size(); i++) {
                Map<String, Object> dataMap = tableDataList.get(i);
                String tempTitle =  (String)dataMap.get(mergeField[0]);
                if(title == null){
                    // 如果是第一行，直接算相等
                    title = tempTitle;
                } else if (title.equals(tempTitle)){
                    rowEnd++;
                    // 如果是最后一条记录，直接添加一个合并单元格
                    if(i == tableDataList.size() - 1){
                        HashMap<String, String> cellsMap = new HashMap<>(1);
                        cellsMap.put("rowCell",rowStart + "," + colStart + "," + rowEnd + "," + colEnd);
                        mergeTableCellList.add(cellsMap);
                    }
                }else{
                    // 记录当前的文本内容
                    title = tempTitle;
                    // 添加一个合并单元格
                    HashMap<String, String> cellsMap = new HashMap<>(1);
                    cellsMap.put("rowCell",rowStart + "," + colStart + "," + rowEnd + "," + colEnd);
                    mergeTableCellList.add(cellsMap);
                    // 重置四个下标
                    rowStart = i + dataRowStartIndex;
                    rowEnd = rowStart;
                }
            }
        }
        // 横向合并，如果指标名称为空，则则与左边单元格进行合并
        for(int i = 0; i < tableDataList.size(); i++) {
            rowStart = dataRowStartIndex + i;
            rowEnd = rowStart;
            colStart = Integer.valueOf(mergeFields[mergeFields.length - 1][1]);
            colEnd = colStart;
            Map<String, Object> stringObjectMap = tableDataList.get(i);
            for(int j = mergeFields.length - 1; j >= 0; j--) {
                String tempTitle = (String)stringObjectMap.get(mergeFields[j][0]);
                if (tempTitle == null){
                    colStart--;
                }else{
                    break;
                }
            }
            HashMap<String, String> cellsMap = new HashMap<>(1);
            cellsMap.put("rowCell",rowStart + "," + colStart + "," + rowEnd + "," + colEnd);
            mergeTableCellList.add(cellsMap);
        }
        return mergeTableCellList;
    }

    /**
     * @描述: 将空字符串转成中横线“ - ”
     * @入参: value 原字符串
     * @入参: defaultValue 源字符串为空时返回的内容
     * @出参:
     * @作者: 陈宏成
     * @日期: 2021/01/14
     **/
    private String convertNullStringToLine(String value,String defaultValue){
        return StringUtils.hasText(value)?value: defaultValue != null ? defaultValue: " - ";
    }

    /**
     * @描述: 保留两位小数
     * @入参: value 原字符串
     * @出参: 如果value为空，返回空字符串，否则保留两位小数
     * @作者: 陈宏成
     * @日期: 2021/01/14
     **/
    private String holdTwoDecimal(String value){
        if(!StringUtils.hasText(value)){
            return "";
        }
        return ConvertUtil.formatNumber(Double.valueOf(value), 2);
    }

    /**
     * @描述: 获取指标范围中文名
     * @入参: scopeValue 指标范围值
     * @作者: 陈宏成
     * @日期: 2021/02/02
     **/
    private String getIdtScopeName(String scopeValue){
        if (!StringUtils.hasText(scopeValue)){
            return "";
        }
        if (scopeValue.toLowerCase().equals(IDT_SCOPE_ALL)){
            return "全域";
        }
        if (scopeValue.toLowerCase().equals(IDT_SCOPE_CITY)){
            return "城区";
        }
        return "";
    }

    /**
     * @描述: 获取指标类型中文名
     * @入参: typeValue 指标类型中文名
     * @作者: 陈宏成
     * @日期: 2021/02/02
     **/
    private String getIdtTypeName(String typeValue){
        if (!StringUtils.hasText(typeValue)){
            return "";
        }
        if (typeValue.toLowerCase().equals(IDT_TYPE_BASIC)){
            return "基本指标";
        }
        if (typeValue.toLowerCase().equals(IDT_TYPE_RECOMMEND)){
            return "推荐指标";
        }
        if (typeValue.toLowerCase().equals(IDT_TYPE_PLACE)){
            return "地方指标";
        }
        return "";
    }

}
